I. Preliminaries

Loading libraries

library("tidyverse")
library("tibble")
library("msigdbr")
library("ggplot2")
library("TCGAbiolinks")
library("RNAseqQC")
library("DESeq2")
library("ensembldb")
library("purrr")
library("magrittr")
library("vsn")
library("matrixStats")
library("dplyr")
library("grex")

II. Downloading the TCGA gene expression data

Create a function for downloading TCGA gene expression data.

For more detailed documentation, refer to 2. Differential Gene Expression Analysis - TCGA.Rmd.

GDC_DIR = "../data/public/GDCdata"

query_and_filter_samples <- function(project) {
  query_tumor <- GDCquery(
    project = project,
    data.category = "Transcriptome Profiling",
    data.type = "Gene Expression Quantification",
    experimental.strategy = "RNA-Seq",
    workflow.type = "STAR - Counts",
    access = "open",
    sample.type = "Primary Tumor"
  )
  tumor <- getResults(query_tumor)

  query_normal <- GDCquery(
    project = project,
    data.category = "Transcriptome Profiling",
    data.type = "Gene Expression Quantification",
    experimental.strategy = "RNA-Seq",
    workflow.type = "STAR - Counts",
    access = "open",
    sample.type = "Solid Tissue Normal"
  )
  normal <- getResults(query_normal)

  submitter_ids <- inner_join(tumor, normal, by = "cases.submitter_id") %>%
    dplyr::select(cases.submitter_id)
  tumor <- tumor %>%
    dplyr::filter(cases.submitter_id %in% submitter_ids$cases.submitter_id)
  normal <- normal %>%
    dplyr::filter(cases.submitter_id %in% submitter_ids$cases.submitter_id)

  samples <- rbind(tumor, normal)
  unique(samples$sample_type)

  query_project <- GDCquery(
    project = project,
    data.category = "Transcriptome Profiling",
    data.type = "Gene Expression Quantification",
    experimental.strategy = "RNA-Seq",
    workflow.type = "STAR - Counts",
    access = "open",
    sample.type = c("Solid Tissue Normal", "Primary Tumor"),
    barcode = as.list(samples$sample.submitter_id)
  )

  # If this is your first time running this notebook (i.e., you have not yet downloaded the results of the query in the previous block),
  # uncomment the code block below

  # GDCdownload(
  #   query_coad,
  #   directory = GDC_DIR
  # )

  return(list(samples = samples, query_project = query_project))
}

Download the TCGA gene expression data for different cancer types.

Refer to this link for the list of TCGA cancer type abbreviations: https://gdc.cancer.gov/resources-tcga-users/tcga-code-tables/tcga-study-abbreviations

projects <- c(
  "TCGA-LUSC", "TCGA-COAD", "TCGA-KICH", "TCGA-KIRC", "TCGA-PRAD",
  "TCGA-BRCA", "TCGA-HNSC", "TCGA-KIRP", "TCGA-LIHC", "TCGA-STAD",
  "TCGA-THCA", "TCGA-BLCA", "TCGA-LUAD", "TCGA-ESCA"
)

samples <- list()
project_data <- list()

for (project in projects) {
  result <- query_and_filter_samples(project)

  samples[[project]] <- result$samples
  project_data[[project]] <- result$query_project
}

Running the code block above should generate and populate a directory named GDCdata.

III. Data preprocessing

Construct the RNA-seq count matrix for each cancer type.

tcga_data <- list()
tcga_matrix <- list()

for (project in projects) {
  tcga_data[[project]] <- GDCprepare(
    project_data[[project]], 
    directory = GDC_DIR,
    summarizedExperiment = TRUE
  )
}
for (project in projects) {
  count_matrix <- assay(tcga_data[[project]], "unstranded")

  # Remove duplicate entries
  count_matrix_df <- data.frame(count_matrix)
  count_matrix_df <- count_matrix_df[!duplicated(count_matrix_df), ]
  count_matrix <- data.matrix(count_matrix_df)
  rownames(count_matrix) <- cleanid(rownames(count_matrix))
  count_matrix <- count_matrix[!(duplicated(rownames(count_matrix)) | duplicated(rownames(count_matrix), fromLast = TRUE)), ]

  tcga_matrix[[project]] <- count_matrix
}

Format the samples table so that it can be fed as input to DESeq2.

for (project in projects) {
  rownames(samples[[project]]) <- samples[[project]]$cases
  samples[[project]] <- samples[[project]] %>%
    dplyr::select(case = "cases.submitter_id", type = "sample_type")
  samples[[project]]$type <- str_replace(samples[[project]]$type, "Solid Tissue Normal", "normal")
  samples[[project]]$type <- str_replace(samples[[project]]$type, "Primary Tumor", "tumor")
}

DESeq2 requires the row names of samples should be identical to the column names of count_matrix.

for (project in projects) {
  colnames(tcga_matrix[[project]]) <- gsub(x = colnames(tcga_matrix[[project]]), pattern = "\\.", replacement = "-")
  tcga_matrix[[project]] <- tcga_matrix[[project]][, rownames(samples[[project]])]

  # Sanity check
  print(all(colnames(tcga_matrix[[project]]) == rownames(samples[[project]])))
}

IV. Differential gene expression analysis

References:

Construct the DESeqDataSet object for each cancer type.

dds_results <- list()

for (project in projects) {
  dds_results[[project]] <- DESeqDataSetFromMatrix(
    countData = tcga_matrix[[project]],
    colData = samples[[project]],
    design = ~type
  )
}
Warning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factorsWarning: some variables in design formula are characters, converting to factors

Regulated Cell Death

Refer to 1. Exploratory Data Analysis - MSigDB Gene Sets + GTEx TPM.Rmd for more detailed documentation on obtaining the gene sets.

Necroptosis

Fetch the necroptosis gene set.

necroptosis.genes <- msigdbr(species = "human", category = "C5", subcategory = "GO:BP") %>%
  dplyr::filter(gs_name == "GOBP_NECROPTOTIC_SIGNALING_PATHWAY")
necroptosis.genes

Filter the genes to include only those in the necroptosis gene set.

tcga_necroptosis <- list()

for (project in projects) {
  rownames(necroptosis.genes) <- necroptosis.genes$ensembl_gene
  tcga_necroptosis[[project]] <- tcga_matrix[[project]][rownames(tcga_matrix[[project]]) %in% necroptosis.genes$ensembl_gene, ]
  tcga_necroptosis[[project]] <- tcga_necroptosis[[project]][, rownames(samples[[project]])]

  # Check if all samples in the counts dataframe are in the samples dataframe
  print(all(colnames(tcga_necroptosis[[project]]) == rownames((samples[[project]]))))
}

Perform differential gene expression analysis.

dds_necroptosis <- list()
res_necroptosis <- list()

for (project in projects) {
  print(project)
  print("=============")

  dds <- DESeqDataSetFromMatrix(
    countData = tcga_necroptosis[[project]],
    colData = samples[[project]],
    design = ~type
  )
  dds <- filter_genes(dds, min_count = 10)
  dds$type <- relevel(dds$type, ref = "normal")
  dds_necroptosis[[project]] <- DESeq(dds)
  res_necroptosis[[project]] <- results(dds_necroptosis[[project]])
}
[1] "TCGA-LUSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-COAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-KICH"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-KIRC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-PRAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-BRCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-HNSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-KIRP"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-LIHC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-STAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-THCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-BLCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-LUAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-ESCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing

Prettify the display of results.

deseq.bbl.data <- list()

for (project in projects) {
  deseq.results <- res_necroptosis[[project]]
  deseq.bbl.data[[project]] <- data.frame(
    row.names = rownames(deseq.results),
    baseMean = deseq.results$baseMean,
    log2FoldChange = deseq.results$log2FoldChange,
    lfcSE = deseq.results$lfcSE,
    stat = deseq.results$stat,
    pvalue = deseq.results$pvalue,
    padj = deseq.results$padj,
    cancer_type = project,
    gene_symbol = necroptosis.genes[rownames(deseq.results), "gene_symbol"]
  )
}

deseq.bbl.data.combined <- bind_rows(deseq.bbl.data)
deseq.bbl.data.combined <- dplyr::filter(deseq.bbl.data.combined, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.combined

Plot the results.

sizes <- c("<10^-15" = 4, "10^-10" = 3, "10^-5" = 2, "0.05" = 1)

deseq.bbl.data.combined <- deseq.bbl.data.combined %>%
  mutate(fdr_category = cut(padj,
    breaks = c(-Inf, 1e-15, 1e-10, 1e-5, 0.05),
    labels = c("<10^-15", "10^-10", "10^-5", "0.05"),
    right = FALSE
  ))

top_genes <- deseq.bbl.data.combined %>%
  group_by(cancer_type) %>%
  mutate(rank = rank(-abs(log2FoldChange))) %>%
  dplyr::filter(rank <= 10) %>%
  ungroup()

ggplot(top_genes, aes(y = cancer_type, x = gene_symbol, size = fdr_category, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size_manual(values = sizes) +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.combined$log2FoldChange), max(deseq.bbl.data.combined$log2FoldChange))) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 9, angle = 90, hjust = 1)
  ) +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "FDR", fill = "log2 FC", y = "Cancer type", x = "Gene")

Ferroptosis

Fetch the ferroptosis gene set.

ferroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:WIKIPATHWAYS") %>%
  dplyr::filter(gs_name == "WP_FERROPTOSIS")
ferroptosis.genes

Filter the genes to include only those in the ferroptosis gene set.

tcga_ferroptosis <- list()

for (project in projects) {
  rownames(ferroptosis.genes) <- ferroptosis.genes$ensembl_gene
  tcga_ferroptosis[[project]] <- tcga_matrix[[project]][rownames(tcga_matrix[[project]]) %in% ferroptosis.genes$ensembl_gene, ]
  tcga_ferroptosis[[project]] <- tcga_ferroptosis[[project]][, rownames(samples[[project]])]

  # Check if all samples in the counts dataframe are in the samples dataframe
  print(all(colnames(tcga_ferroptosis[[project]]) == rownames((samples[[project]]))))
}

Perform differential gene expression analysis.

dds_ferroptosis <- list()
res_ferroptosis <- list()

for (project in projects) {
  print(project)
  print("=============")

  dds <- DESeqDataSetFromMatrix(
    countData = tcga_ferroptosis[[project]],
    colData = samples[[project]],
    design = ~type
  )
  dds <- filter_genes(dds, min_count = 10)
  dds$type <- relevel(dds$type, ref = "normal")
  dds_ferroptosis[[project]] <- DESeq(dds)
  res_ferroptosis[[project]] <- results(dds_ferroptosis[[project]])
}
[1] "TCGA-LUSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-COAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-KICH"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-KIRC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-PRAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-BRCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-HNSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-KIRP"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-LIHC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 4 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-STAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 4 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-THCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-BLCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 8 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-LUAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-ESCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing

Prettify the display of results.

deseq.bbl.data <- list()

for (project in projects) {
  deseq.results <- res_ferroptosis[[project]]
  deseq.bbl.data[[project]] <- data.frame(
    row.names = rownames(deseq.results),
    baseMean = deseq.results$baseMean,
    log2FoldChange = deseq.results$log2FoldChange,
    lfcSE = deseq.results$lfcSE,
    stat = deseq.results$stat,
    pvalue = deseq.results$pvalue,
    padj = deseq.results$padj,
    cancer_type = project,
    gene_symbol = ferroptosis.genes[rownames(deseq.results), "gene_symbol"]
  )
}

deseq.bbl.data.combined <- bind_rows(deseq.bbl.data)
deseq.bbl.data.combined <- dplyr::filter(deseq.bbl.data.combined, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.combined

Plot the results.

deseq.bbl.data.combined <- deseq.bbl.data.combined %>%
  mutate(fdr_category = cut(padj,
    breaks = c(-Inf, 1e-15, 1e-10, 1e-5, 0.05),
    labels = c("<10^-15", "10^-10", "10^-5", "0.05"),
    right = FALSE
  ))

top_genes <- deseq.bbl.data.combined %>%
  group_by(cancer_type) %>%
  mutate(rank = rank(-abs(log2FoldChange))) %>%
  dplyr::filter(rank <= 10) %>%
  ungroup()

ggplot(top_genes, aes(y = cancer_type, x = gene_symbol, size = fdr_category, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size_manual(values = sizes) +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.combined$log2FoldChange), max(deseq.bbl.data.combined$log2FoldChange))) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 9, angle = 90, hjust = 1)
  ) +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "FDR", fill = "log2 FC", y = "Cancer type", x = "Gene")

Pyroptosis

Fetch the pyroptosis gene set.

pyroptosis.genes <- msigdbr(species = "human", category = "C2", subcategory = "CP:REACTOME") %>%
  dplyr::filter(gs_name == "REACTOME_PYROPTOSIS")
pyroptosis.genes

Filter the genes to include only those in the pyroptosis gene set.

tcga_pyroptosis <- list()

for (project in projects) {
  rownames(pyroptosis.genes) <- pyroptosis.genes$ensembl_gene
  tcga_pyroptosis[[project]] <- tcga_matrix[[project]][rownames(tcga_matrix[[project]]) %in% pyroptosis.genes$ensembl_gene, ]
  tcga_pyroptosis[[project]] <- tcga_pyroptosis[[project]][, rownames(samples[[project]])]

  # Check if all samples in the counts dataframe are in the samples dataframe
  print(all(colnames(tcga_pyroptosis[[project]]) == rownames((samples[[project]]))))
}

Perform differential gene expression analysis.

dds_pyroptosis <- list()
res_pyroptosis <- list()

for (project in projects) {
  print(project)
  print("=============")

  dds <- DESeqDataSetFromMatrix(
    countData = tcga_pyroptosis[[project]],
    colData = samples[[project]],
    design = ~type
  )
  dds <- filter_genes(dds, min_count = 10)
  dds$type <- relevel(dds$type, ref = "normal")
  dds_pyroptosis[[project]] <- DESeq(dds)
  res_pyroptosis[[project]] <- results(dds_pyroptosis[[project]])
}
[1] "TCGA-LUSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-COAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-KICH"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-KIRC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 3 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-PRAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-BRCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-HNSC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-KIRP"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
[1] "TCGA-LIHC"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-STAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-THCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 2 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-BLCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-LUAD"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing
[1] "TCGA-ESCA"
[1] "============="
Warning: some variables in design formula are characters, converting to factorsestimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
-- replacing outliers and refitting for 1 genes
-- DESeq argument 'minReplicatesForReplace' = 7 
-- original counts are preserved in counts(dds)
estimating dispersions
fitting model and testing

Prettify the display of results.

deseq.bbl.data <- list()

for (project in projects) {
  deseq.results <- res_pyroptosis[[project]]
  deseq.bbl.data[[project]] <- data.frame(
    row.names = rownames(deseq.results),
    baseMean = deseq.results$baseMean,
    log2FoldChange = deseq.results$log2FoldChange,
    lfcSE = deseq.results$lfcSE,
    stat = deseq.results$stat,
    pvalue = deseq.results$pvalue,
    padj = deseq.results$padj,
    cancer_type = project,
    gene_symbol = pyroptosis.genes[rownames(deseq.results), "gene_symbol"]
  )
}

deseq.bbl.data.combined <- bind_rows(deseq.bbl.data)
deseq.bbl.data.combined <- dplyr::filter(deseq.bbl.data.combined, abs(log2FoldChange) >= 1.5 & padj < 0.05)
deseq.bbl.data.combined

Plot the results.

deseq.bbl.data.combined <- deseq.bbl.data.combined %>%
  mutate(fdr_category = cut(padj,
    breaks = c(-Inf, 1e-15, 1e-10, 1e-5, 0.05),
    labels = c("<10^-15", "10^-10", "10^-5", "0.05"),
    right = FALSE
  ))

top_genes <- deseq.bbl.data.combined %>%
  group_by(cancer_type) %>%
  mutate(rank = rank(-abs(log2FoldChange))) %>%
  dplyr::filter(rank <= 10) %>%
  ungroup()

ggplot(top_genes, aes(y = cancer_type, x = gene_symbol, size = fdr_category, fill = log2FoldChange)) +
  geom_point(alpha = 0.5, shape = 21, color = "black") +
  scale_size_manual(values = sizes) +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", limits = c(min(deseq.bbl.data.combined$log2FoldChange), max(deseq.bbl.data.combined$log2FoldChange))) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 9, angle = 90, hjust = 1)
  ) +
  theme(legend.position = "bottom") +
  theme(legend.position = "bottom") +
  labs(size = "FDR", fill = "log2 FC", y = "Cancer type", x = "Gene")


  1. De La Salle University, Manila, Philippines, ↩︎

  2. De La Salle University, Manila, Philippines, ↩︎

  3. De La Salle University, Manila, Philippines, ↩︎

LS0tDQp0aXRsZTogIkRpZmZlcmVudGlhbCBHZW5lIEV4cHJlc3Npb24gQW5hbHlzaXMiDQpzdWJ0aXRsZTogIlBhbi1jYW5jZXIgfCBOZWNyb3B0b3NpcywgRmVycm9wdG9zaXMgJiBQeXJvcHRvc2lzIg0KYXV0aG9yOiANCiAgLSBLaW0gV2lsbGlhbWUgTGVlXltEZSBMYSBTYWxsZSBVbml2ZXJzaXR5LCBNYW5pbGEsIFBoaWxpcHBpbmVzLCBraW1fbGVlanJhQGRsc3UuZWR1LnBoXQ0KICAtIE1hcmsgRWR3YXJkIE0uIEdvbnphbGVzXltEZSBMYSBTYWxsZSBVbml2ZXJzaXR5LCBNYW5pbGEsIFBoaWxpcHBpbmVzLCBnb256YWxlcy5tYXJrZWR3YXJkQGdtYWlsLmNvbV0NCiAgLSBEci4gQW5pc2ggTS5TLiBTaHJlc3RoYV5bRGUgTGEgU2FsbGUgVW5pdmVyc2l0eSwgTWFuaWxhLCBQaGlsaXBwaW5lcywgYW5pc2guc2hyZXN0aGFAZGxzdS5lZHUucGhdDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBJLiBQcmVsaW1pbmFyaWVzDQoNCiMjIyBMb2FkaW5nIGxpYnJhcmllcw0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KCJ0aWJibGUiKQ0KbGlicmFyeSgibXNpZ2RiciIpDQpsaWJyYXJ5KCJnZ3Bsb3QyIikNCmxpYnJhcnkoIlRDR0FiaW9saW5rcyIpDQpsaWJyYXJ5KCJSTkFzZXFRQyIpDQpsaWJyYXJ5KCJERVNlcTIiKQ0KbGlicmFyeSgiZW5zZW1ibGRiIikNCmxpYnJhcnkoInB1cnJyIikNCmxpYnJhcnkoIm1hZ3JpdHRyIikNCmxpYnJhcnkoInZzbiIpDQpsaWJyYXJ5KCJtYXRyaXhTdGF0cyIpDQpsaWJyYXJ5KCJkcGx5ciIpDQpsaWJyYXJ5KCJncmV4IikNCmBgYA0KDQojIyBJSS4gRG93bmxvYWRpbmcgdGhlIFRDR0EgZ2VuZSBleHByZXNzaW9uIGRhdGEgDQoNCkNyZWF0ZSBhIGZ1bmN0aW9uIGZvciBkb3dubG9hZGluZyBUQ0dBIGdlbmUgZXhwcmVzc2lvbiBkYXRhLiANCg0KRm9yIG1vcmUgZGV0YWlsZWQgZG9jdW1lbnRhdGlvbiwgcmVmZXIgdG8gYDIuIERpZmZlcmVudGlhbCBHZW5lIEV4cHJlc3Npb24gQW5hbHlzaXMgLSBUQ0dBLlJtZGAuDQoNCmBgYHtyfQ0KR0RDX0RJUiA9ICIuLi9kYXRhL3B1YmxpYy9HRENkYXRhIg0KDQpxdWVyeV9hbmRfZmlsdGVyX3NhbXBsZXMgPC0gZnVuY3Rpb24ocHJvamVjdCkgew0KICBxdWVyeV90dW1vciA8LSBHRENxdWVyeSgNCiAgICBwcm9qZWN0ID0gcHJvamVjdCwNCiAgICBkYXRhLmNhdGVnb3J5ID0gIlRyYW5zY3JpcHRvbWUgUHJvZmlsaW5nIiwNCiAgICBkYXRhLnR5cGUgPSAiR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uIiwNCiAgICBleHBlcmltZW50YWwuc3RyYXRlZ3kgPSAiUk5BLVNlcSIsDQogICAgd29ya2Zsb3cudHlwZSA9ICJTVEFSIC0gQ291bnRzIiwNCiAgICBhY2Nlc3MgPSAib3BlbiIsDQogICAgc2FtcGxlLnR5cGUgPSAiUHJpbWFyeSBUdW1vciINCiAgKQ0KICB0dW1vciA8LSBnZXRSZXN1bHRzKHF1ZXJ5X3R1bW9yKQ0KDQogIHF1ZXJ5X25vcm1hbCA8LSBHRENxdWVyeSgNCiAgICBwcm9qZWN0ID0gcHJvamVjdCwNCiAgICBkYXRhLmNhdGVnb3J5ID0gIlRyYW5zY3JpcHRvbWUgUHJvZmlsaW5nIiwNCiAgICBkYXRhLnR5cGUgPSAiR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uIiwNCiAgICBleHBlcmltZW50YWwuc3RyYXRlZ3kgPSAiUk5BLVNlcSIsDQogICAgd29ya2Zsb3cudHlwZSA9ICJTVEFSIC0gQ291bnRzIiwNCiAgICBhY2Nlc3MgPSAib3BlbiIsDQogICAgc2FtcGxlLnR5cGUgPSAiU29saWQgVGlzc3VlIE5vcm1hbCINCiAgKQ0KICBub3JtYWwgPC0gZ2V0UmVzdWx0cyhxdWVyeV9ub3JtYWwpDQoNCiAgc3VibWl0dGVyX2lkcyA8LSBpbm5lcl9qb2luKHR1bW9yLCBub3JtYWwsIGJ5ID0gImNhc2VzLnN1Ym1pdHRlcl9pZCIpICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoY2FzZXMuc3VibWl0dGVyX2lkKQ0KICB0dW1vciA8LSB0dW1vciAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKGNhc2VzLnN1Ym1pdHRlcl9pZCAlaW4lIHN1Ym1pdHRlcl9pZHMkY2FzZXMuc3VibWl0dGVyX2lkKQ0KICBub3JtYWwgPC0gbm9ybWFsICU+JQ0KICAgIGRwbHlyOjpmaWx0ZXIoY2FzZXMuc3VibWl0dGVyX2lkICVpbiUgc3VibWl0dGVyX2lkcyRjYXNlcy5zdWJtaXR0ZXJfaWQpDQoNCiAgc2FtcGxlcyA8LSByYmluZCh0dW1vciwgbm9ybWFsKQ0KICB1bmlxdWUoc2FtcGxlcyRzYW1wbGVfdHlwZSkNCg0KICBxdWVyeV9wcm9qZWN0IDwtIEdEQ3F1ZXJ5KA0KICAgIHByb2plY3QgPSBwcm9qZWN0LA0KICAgIGRhdGEuY2F0ZWdvcnkgPSAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciLA0KICAgIGRhdGEudHlwZSA9ICJHZW5lIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24iLA0KICAgIGV4cGVyaW1lbnRhbC5zdHJhdGVneSA9ICJSTkEtU2VxIiwNCiAgICB3b3JrZmxvdy50eXBlID0gIlNUQVIgLSBDb3VudHMiLA0KICAgIGFjY2VzcyA9ICJvcGVuIiwNCiAgICBzYW1wbGUudHlwZSA9IGMoIlNvbGlkIFRpc3N1ZSBOb3JtYWwiLCAiUHJpbWFyeSBUdW1vciIpLA0KICAgIGJhcmNvZGUgPSBhcy5saXN0KHNhbXBsZXMkc2FtcGxlLnN1Ym1pdHRlcl9pZCkNCiAgKQ0KDQogICMgSWYgdGhpcyBpcyB5b3VyIGZpcnN0IHRpbWUgcnVubmluZyB0aGlzIG5vdGVib29rIChpLmUuLCB5b3UgaGF2ZSBub3QgeWV0IGRvd25sb2FkZWQgdGhlIHJlc3VsdHMgb2YgdGhlIHF1ZXJ5IGluIHRoZSBwcmV2aW91cyBibG9jayksDQogICMgdW5jb21tZW50IHRoZSBjb2RlIGJsb2NrIGJlbG93DQoNCiAgIyBHRENkb3dubG9hZCgNCiAgIyAgIHF1ZXJ5X2NvYWQsDQogICMgICBkaXJlY3RvcnkgPSBHRENfRElSDQogICMgKQ0KDQogIHJldHVybihsaXN0KHNhbXBsZXMgPSBzYW1wbGVzLCBxdWVyeV9wcm9qZWN0ID0gcXVlcnlfcHJvamVjdCkpDQp9DQpgYGANCg0KRG93bmxvYWQgdGhlIFRDR0EgZ2VuZSBleHByZXNzaW9uIGRhdGEgZm9yIGRpZmZlcmVudCBjYW5jZXIgdHlwZXMuDQoNClJlZmVyIHRvIHRoaXMgbGluayBmb3IgdGhlIGxpc3Qgb2YgVENHQSBjYW5jZXIgdHlwZSBhYmJyZXZpYXRpb25zOiBodHRwczovL2dkYy5jYW5jZXIuZ292L3Jlc291cmNlcy10Y2dhLXVzZXJzL3RjZ2EtY29kZS10YWJsZXMvdGNnYS1zdHVkeS1hYmJyZXZpYXRpb25zDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KcHJvamVjdHMgPC0gYygNCiAgIlRDR0EtTFVTQyIsICJUQ0dBLUNPQUQiLCAiVENHQS1LSUNIIiwgIlRDR0EtS0lSQyIsICJUQ0dBLVBSQUQiLA0KICAiVENHQS1CUkNBIiwgIlRDR0EtSE5TQyIsICJUQ0dBLUtJUlAiLCAiVENHQS1MSUhDIiwgIlRDR0EtU1RBRCIsDQogICJUQ0dBLVRIQ0EiLCAiVENHQS1CTENBIiwgIlRDR0EtTFVBRCIsICJUQ0dBLUVTQ0EiDQopDQoNCnNhbXBsZXMgPC0gbGlzdCgpDQpwcm9qZWN0X2RhdGEgPC0gbGlzdCgpDQoNCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICByZXN1bHQgPC0gcXVlcnlfYW5kX2ZpbHRlcl9zYW1wbGVzKHByb2plY3QpDQoNCiAgc2FtcGxlc1tbcHJvamVjdF1dIDwtIHJlc3VsdCRzYW1wbGVzDQogIHByb2plY3RfZGF0YVtbcHJvamVjdF1dIDwtIHJlc3VsdCRxdWVyeV9wcm9qZWN0DQp9DQpgYGANCg0KDQpSdW5uaW5nIHRoZSBjb2RlIGJsb2NrIGFib3ZlIHNob3VsZCBnZW5lcmF0ZSBhbmQgcG9wdWxhdGUgYSBkaXJlY3RvcnkgbmFtZWQgYEdEQ2RhdGFgLg0KDQojIyBJSUkuIERhdGEgcHJlcHJvY2Vzc2luZw0KDQpDb25zdHJ1Y3QgdGhlIFJOQS1zZXEgY291bnQgbWF0cml4IGZvciBlYWNoIGNhbmNlciB0eXBlLg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgcmVzdWx0cz0iaGlkZSJ9DQp0Y2dhX2RhdGEgPC0gbGlzdCgpDQp0Y2dhX21hdHJpeCA8LSBsaXN0KCkNCg0KZm9yIChwcm9qZWN0IGluIHByb2plY3RzKSB7DQogIHRjZ2FfZGF0YVtbcHJvamVjdF1dIDwtIEdEQ3ByZXBhcmUoDQogICAgcHJvamVjdF9kYXRhW1twcm9qZWN0XV0sIA0KICAgIGRpcmVjdG9yeSA9IEdEQ19ESVIsDQogICAgc3VtbWFyaXplZEV4cGVyaW1lbnQgPSBUUlVFDQogICkNCn0NCmBgYA0KDQpgYGB7cn0NCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICBjb3VudF9tYXRyaXggPC0gYXNzYXkodGNnYV9kYXRhW1twcm9qZWN0XV0sICJ1bnN0cmFuZGVkIikNCg0KICAjIFJlbW92ZSBkdXBsaWNhdGUgZW50cmllcw0KICBjb3VudF9tYXRyaXhfZGYgPC0gZGF0YS5mcmFtZShjb3VudF9tYXRyaXgpDQogIGNvdW50X21hdHJpeF9kZiA8LSBjb3VudF9tYXRyaXhfZGZbIWR1cGxpY2F0ZWQoY291bnRfbWF0cml4X2RmKSwgXQ0KICBjb3VudF9tYXRyaXggPC0gZGF0YS5tYXRyaXgoY291bnRfbWF0cml4X2RmKQ0KICByb3duYW1lcyhjb3VudF9tYXRyaXgpIDwtIGNsZWFuaWQocm93bmFtZXMoY291bnRfbWF0cml4KSkNCiAgY291bnRfbWF0cml4IDwtIGNvdW50X21hdHJpeFshKGR1cGxpY2F0ZWQocm93bmFtZXMoY291bnRfbWF0cml4KSkgfCBkdXBsaWNhdGVkKHJvd25hbWVzKGNvdW50X21hdHJpeCksIGZyb21MYXN0ID0gVFJVRSkpLCBdDQoNCiAgdGNnYV9tYXRyaXhbW3Byb2plY3RdXSA8LSBjb3VudF9tYXRyaXgNCn0NCmBgYA0KRm9ybWF0IHRoZSBgc2FtcGxlc2AgdGFibGUgc28gdGhhdCBpdCBjYW4gYmUgZmVkIGFzIGlucHV0IHRvIERFU2VxMi4NCg0KYGBge3J9DQpmb3IgKHByb2plY3QgaW4gcHJvamVjdHMpIHsNCiAgcm93bmFtZXMoc2FtcGxlc1tbcHJvamVjdF1dKSA8LSBzYW1wbGVzW1twcm9qZWN0XV0kY2FzZXMNCiAgc2FtcGxlc1tbcHJvamVjdF1dIDwtIHNhbXBsZXNbW3Byb2plY3RdXSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGNhc2UgPSAiY2FzZXMuc3VibWl0dGVyX2lkIiwgdHlwZSA9ICJzYW1wbGVfdHlwZSIpDQogIHNhbXBsZXNbW3Byb2plY3RdXSR0eXBlIDwtIHN0cl9yZXBsYWNlKHNhbXBsZXNbW3Byb2plY3RdXSR0eXBlLCAiU29saWQgVGlzc3VlIE5vcm1hbCIsICJub3JtYWwiKQ0KICBzYW1wbGVzW1twcm9qZWN0XV0kdHlwZSA8LSBzdHJfcmVwbGFjZShzYW1wbGVzW1twcm9qZWN0XV0kdHlwZSwgIlByaW1hcnkgVHVtb3IiLCAidHVtb3IiKQ0KfQ0KYGBgDQoNCkRFU2VxMiByZXF1aXJlcyB0aGUgcm93IG5hbWVzIG9mIGBzYW1wbGVzYCBzaG91bGQgYmUgaWRlbnRpY2FsIHRvIHRoZSBjb2x1bW4gbmFtZXMgb2YgYGNvdW50X21hdHJpeGAuDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgcmVzdWx0cz0iaGlkZSJ9DQpmb3IgKHByb2plY3QgaW4gcHJvamVjdHMpIHsNCiAgY29sbmFtZXModGNnYV9tYXRyaXhbW3Byb2plY3RdXSkgPC0gZ3N1Yih4ID0gY29sbmFtZXModGNnYV9tYXRyaXhbW3Byb2plY3RdXSksIHBhdHRlcm4gPSAiXFwuIiwgcmVwbGFjZW1lbnQgPSAiLSIpDQogIHRjZ2FfbWF0cml4W1twcm9qZWN0XV0gPC0gdGNnYV9tYXRyaXhbW3Byb2plY3RdXVssIHJvd25hbWVzKHNhbXBsZXNbW3Byb2plY3RdXSldDQoNCiAgIyBTYW5pdHkgY2hlY2sNCiAgcHJpbnQoYWxsKGNvbG5hbWVzKHRjZ2FfbWF0cml4W1twcm9qZWN0XV0pID09IHJvd25hbWVzKHNhbXBsZXNbW3Byb2plY3RdXSkpKQ0KfQ0KYGBgDQoNCiMjIElWLiBEaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzDQoNClJlZmVyZW5jZXM6IA0KDQotIE9mZmljaWFsIGRvY3VtZW50YXRpb246IGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL3ZpZ25ldHRlcy9ERVNlcTIvaW5zdC9kb2MvREVTZXEyLmh0bWwNCi0gR29vZCBiYWxhbmNlIG9mIHRoZW9yeSBhbmQgaGFuZHMtb246IGh0dHBzOi8vaGJjdHJhaW5pbmcuZ2l0aHViLmlvL0RHRV93b3Jrc2hvcC9sZXNzb25zLzA0X0RHRV9ERVNlcTJfYW5hbHlzaXMuaHRtbA0KLSBRdWFsaXR5IGNvbnRyb2w6IGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9STkFzZXFRQy92aWduZXR0ZXMvaW50cm9kdWN0aW9uLmh0bWwNCg0KQ29uc3RydWN0IHRoZSBgREVTZXFEYXRhU2V0YCBvYmplY3QgZm9yIGVhY2ggY2FuY2VyIHR5cGUuDQoNCmBgYHtyfQ0KZGRzX3Jlc3VsdHMgPC0gbGlzdCgpDQoNCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICBkZHNfcmVzdWx0c1tbcHJvamVjdF1dIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoDQogICAgY291bnREYXRhID0gdGNnYV9tYXRyaXhbW3Byb2plY3RdXSwNCiAgICBjb2xEYXRhID0gc2FtcGxlc1tbcHJvamVjdF1dLA0KICAgIGRlc2lnbiA9IH50eXBlDQogICkNCn0NCmBgYA0KDQoNCiMjIyBSZWd1bGF0ZWQgQ2VsbCBEZWF0aA0KDQpSZWZlciB0byBgMS4gRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAtIE1TaWdEQiBHZW5lIFNldHMgKyBHVEV4IFRQTS5SbWRgIGZvciBtb3JlIGRldGFpbGVkIGRvY3VtZW50YXRpb24gb24gb2J0YWluaW5nIHRoZSBnZW5lIHNldHMuDQoNCiMjIyMgTmVjcm9wdG9zaXMNCg0KRmV0Y2ggdGhlIG5lY3JvcHRvc2lzIGdlbmUgc2V0Lg0KDQpgYGB7cn0NCm5lY3JvcHRvc2lzLmdlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJodW1hbiIsIGNhdGVnb3J5ID0gIkM1Iiwgc3ViY2F0ZWdvcnkgPSAiR086QlAiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihnc19uYW1lID09ICJHT0JQX05FQ1JPUFRPVElDX1NJR05BTElOR19QQVRIV0FZIikNCm5lY3JvcHRvc2lzLmdlbmVzDQpgYGANCkZpbHRlciB0aGUgZ2VuZXMgdG8gaW5jbHVkZSBvbmx5IHRob3NlIGluIHRoZSBuZWNyb3B0b3NpcyBnZW5lIHNldC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCByZXN1bHRzPSJoaWRlIn0NCnRjZ2FfbmVjcm9wdG9zaXMgPC0gbGlzdCgpDQoNCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICByb3duYW1lcyhuZWNyb3B0b3Npcy5nZW5lcykgPC0gbmVjcm9wdG9zaXMuZ2VuZXMkZW5zZW1ibF9nZW5lDQogIHRjZ2FfbmVjcm9wdG9zaXNbW3Byb2plY3RdXSA8LSB0Y2dhX21hdHJpeFtbcHJvamVjdF1dW3Jvd25hbWVzKHRjZ2FfbWF0cml4W1twcm9qZWN0XV0pICVpbiUgbmVjcm9wdG9zaXMuZ2VuZXMkZW5zZW1ibF9nZW5lLCBdDQogIHRjZ2FfbmVjcm9wdG9zaXNbW3Byb2plY3RdXSA8LSB0Y2dhX25lY3JvcHRvc2lzW1twcm9qZWN0XV1bLCByb3duYW1lcyhzYW1wbGVzW1twcm9qZWN0XV0pXQ0KDQogICMgQ2hlY2sgaWYgYWxsIHNhbXBsZXMgaW4gdGhlIGNvdW50cyBkYXRhZnJhbWUgYXJlIGluIHRoZSBzYW1wbGVzIGRhdGFmcmFtZQ0KICBwcmludChhbGwoY29sbmFtZXModGNnYV9uZWNyb3B0b3Npc1tbcHJvamVjdF1dKSA9PSByb3duYW1lcygoc2FtcGxlc1tbcHJvamVjdF1dKSkpKQ0KfQ0KYGBgDQoNClBlcmZvcm0gZGlmZmVyZW50aWFsIGdlbmUgZXhwcmVzc2lvbiBhbmFseXNpcy4NCg0KYGBge3J9DQpkZHNfbmVjcm9wdG9zaXMgPC0gbGlzdCgpDQpyZXNfbmVjcm9wdG9zaXMgPC0gbGlzdCgpDQoNCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICBwcmludChwcm9qZWN0KQ0KICBwcmludCgiPT09PT09PT09PT09PSIpDQoNCiAgZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoDQogICAgY291bnREYXRhID0gdGNnYV9uZWNyb3B0b3Npc1tbcHJvamVjdF1dLA0KICAgIGNvbERhdGEgPSBzYW1wbGVzW1twcm9qZWN0XV0sDQogICAgZGVzaWduID0gfnR5cGUNCiAgKQ0KICBkZHMgPC0gZmlsdGVyX2dlbmVzKGRkcywgbWluX2NvdW50ID0gMTApDQogIGRkcyR0eXBlIDwtIHJlbGV2ZWwoZGRzJHR5cGUsIHJlZiA9ICJub3JtYWwiKQ0KICBkZHNfbmVjcm9wdG9zaXNbW3Byb2plY3RdXSA8LSBERVNlcShkZHMpDQogIHJlc19uZWNyb3B0b3Npc1tbcHJvamVjdF1dIDwtIHJlc3VsdHMoZGRzX25lY3JvcHRvc2lzW1twcm9qZWN0XV0pDQp9DQpgYGANCg0KUHJldHRpZnkgdGhlIGRpc3BsYXkgb2YgcmVzdWx0cy4NCg0KYGBge3J9DQpkZXNlcS5iYmwuZGF0YSA8LSBsaXN0KCkNCg0KZm9yIChwcm9qZWN0IGluIHByb2plY3RzKSB7DQogIGRlc2VxLnJlc3VsdHMgPC0gcmVzX25lY3JvcHRvc2lzW1twcm9qZWN0XV0NCiAgZGVzZXEuYmJsLmRhdGFbW3Byb2plY3RdXSA8LSBkYXRhLmZyYW1lKA0KICAgIHJvdy5uYW1lcyA9IHJvd25hbWVzKGRlc2VxLnJlc3VsdHMpLA0KICAgIGJhc2VNZWFuID0gZGVzZXEucmVzdWx0cyRiYXNlTWVhbiwNCiAgICBsb2cyRm9sZENoYW5nZSA9IGRlc2VxLnJlc3VsdHMkbG9nMkZvbGRDaGFuZ2UsDQogICAgbGZjU0UgPSBkZXNlcS5yZXN1bHRzJGxmY1NFLA0KICAgIHN0YXQgPSBkZXNlcS5yZXN1bHRzJHN0YXQsDQogICAgcHZhbHVlID0gZGVzZXEucmVzdWx0cyRwdmFsdWUsDQogICAgcGFkaiA9IGRlc2VxLnJlc3VsdHMkcGFkaiwNCiAgICBjYW5jZXJfdHlwZSA9IHByb2plY3QsDQogICAgZ2VuZV9zeW1ib2wgPSBuZWNyb3B0b3Npcy5nZW5lc1tyb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwgImdlbmVfc3ltYm9sIl0NCiAgKQ0KfQ0KDQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCA8LSBiaW5kX3Jvd3MoZGVzZXEuYmJsLmRhdGEpDQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCA8LSBkcGx5cjo6ZmlsdGVyKGRlc2VxLmJibC5kYXRhLmNvbWJpbmVkLCBhYnMobG9nMkZvbGRDaGFuZ2UpID49IDEuNSAmIHBhZGogPCAwLjA1KQ0KZGVzZXEuYmJsLmRhdGEuY29tYmluZWQNCmBgYA0KDQpQbG90IHRoZSByZXN1bHRzLg0KDQpgYGB7cn0NCnNpemVzIDwtIGMoIjwxMF4tMTUiID0gNCwgIjEwXi0xMCIgPSAzLCAiMTBeLTUiID0gMiwgIjAuMDUiID0gMSkNCg0KZGVzZXEuYmJsLmRhdGEuY29tYmluZWQgPC0gZGVzZXEuYmJsLmRhdGEuY29tYmluZWQgJT4lDQogIG11dGF0ZShmZHJfY2F0ZWdvcnkgPSBjdXQocGFkaiwNCiAgICBicmVha3MgPSBjKC1JbmYsIDFlLTE1LCAxZS0xMCwgMWUtNSwgMC4wNSksDQogICAgbGFiZWxzID0gYygiPDEwXi0xNSIsICIxMF4tMTAiLCAiMTBeLTUiLCAiMC4wNSIpLA0KICAgIHJpZ2h0ID0gRkFMU0UNCiAgKSkNCg0KdG9wX2dlbmVzIDwtIGRlc2VxLmJibC5kYXRhLmNvbWJpbmVkICU+JQ0KICBncm91cF9ieShjYW5jZXJfdHlwZSkgJT4lDQogIG11dGF0ZShyYW5rID0gcmFuaygtYWJzKGxvZzJGb2xkQ2hhbmdlKSkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHJhbmsgPD0gMTApICU+JQ0KICB1bmdyb3VwKCkNCg0KZ2dwbG90KHRvcF9nZW5lcywgYWVzKHkgPSBjYW5jZXJfdHlwZSwgeCA9IGdlbmVfc3ltYm9sLCBzaXplID0gZmRyX2NhdGVnb3J5LCBmaWxsID0gbG9nMkZvbGRDaGFuZ2UpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIikgKw0KICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSBzaXplcykgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbGltaXRzID0gYyhtaW4oZGVzZXEuYmJsLmRhdGEuY29tYmluZWQkbG9nMkZvbGRDaGFuZ2UpLCBtYXgoZGVzZXEuYmJsLmRhdGEuY29tYmluZWQkbG9nMkZvbGRDaGFuZ2UpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgYW5nbGUgPSA5MCwgaGp1c3QgPSAxKQ0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgbGFicyhzaXplID0gIkZEUiIsIGZpbGwgPSAibG9nMiBGQyIsIHkgPSAiQ2FuY2VyIHR5cGUiLCB4ID0gIkdlbmUiKQ0KYGBgDQoNCiMjIyMgRmVycm9wdG9zaXMNCg0KRmV0Y2ggdGhlIGZlcnJvcHRvc2lzIGdlbmUgc2V0Lg0KDQpgYGB7cn0NCmZlcnJvcHRvc2lzLmdlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJodW1hbiIsIGNhdGVnb3J5ID0gIkMyIiwgc3ViY2F0ZWdvcnkgPSAiQ1A6V0lLSVBBVEhXQVlTIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoZ3NfbmFtZSA9PSAiV1BfRkVSUk9QVE9TSVMiKQ0KZmVycm9wdG9zaXMuZ2VuZXMNCmBgYA0KDQpGaWx0ZXIgdGhlIGdlbmVzIHRvIGluY2x1ZGUgb25seSB0aG9zZSBpbiB0aGUgZmVycm9wdG9zaXMgZ2VuZSBzZXQuDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgcmVzdWx0cz0iaGlkZSJ9DQp0Y2dhX2ZlcnJvcHRvc2lzIDwtIGxpc3QoKQ0KDQpmb3IgKHByb2plY3QgaW4gcHJvamVjdHMpIHsNCiAgcm93bmFtZXMoZmVycm9wdG9zaXMuZ2VuZXMpIDwtIGZlcnJvcHRvc2lzLmdlbmVzJGVuc2VtYmxfZ2VuZQ0KICB0Y2dhX2ZlcnJvcHRvc2lzW1twcm9qZWN0XV0gPC0gdGNnYV9tYXRyaXhbW3Byb2plY3RdXVtyb3duYW1lcyh0Y2dhX21hdHJpeFtbcHJvamVjdF1dKSAlaW4lIGZlcnJvcHRvc2lzLmdlbmVzJGVuc2VtYmxfZ2VuZSwgXQ0KICB0Y2dhX2ZlcnJvcHRvc2lzW1twcm9qZWN0XV0gPC0gdGNnYV9mZXJyb3B0b3Npc1tbcHJvamVjdF1dWywgcm93bmFtZXMoc2FtcGxlc1tbcHJvamVjdF1dKV0NCg0KICAjIENoZWNrIGlmIGFsbCBzYW1wbGVzIGluIHRoZSBjb3VudHMgZGF0YWZyYW1lIGFyZSBpbiB0aGUgc2FtcGxlcyBkYXRhZnJhbWUNCiAgcHJpbnQoYWxsKGNvbG5hbWVzKHRjZ2FfZmVycm9wdG9zaXNbW3Byb2plY3RdXSkgPT0gcm93bmFtZXMoKHNhbXBsZXNbW3Byb2plY3RdXSkpKSkNCn0NCmBgYA0KUGVyZm9ybSBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzLg0KDQpgYGB7cn0NCmRkc19mZXJyb3B0b3NpcyA8LSBsaXN0KCkNCnJlc19mZXJyb3B0b3NpcyA8LSBsaXN0KCkNCg0KZm9yIChwcm9qZWN0IGluIHByb2plY3RzKSB7DQogIHByaW50KHByb2plY3QpDQogIHByaW50KCI9PT09PT09PT09PT09IikNCg0KICBkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeCgNCiAgICBjb3VudERhdGEgPSB0Y2dhX2ZlcnJvcHRvc2lzW1twcm9qZWN0XV0sDQogICAgY29sRGF0YSA9IHNhbXBsZXNbW3Byb2plY3RdXSwNCiAgICBkZXNpZ24gPSB+dHlwZQ0KICApDQogIGRkcyA8LSBmaWx0ZXJfZ2VuZXMoZGRzLCBtaW5fY291bnQgPSAxMCkNCiAgZGRzJHR5cGUgPC0gcmVsZXZlbChkZHMkdHlwZSwgcmVmID0gIm5vcm1hbCIpDQogIGRkc19mZXJyb3B0b3Npc1tbcHJvamVjdF1dIDwtIERFU2VxKGRkcykNCiAgcmVzX2ZlcnJvcHRvc2lzW1twcm9qZWN0XV0gPC0gcmVzdWx0cyhkZHNfZmVycm9wdG9zaXNbW3Byb2plY3RdXSkNCn0NCmBgYA0KDQpQcmV0dGlmeSB0aGUgZGlzcGxheSBvZiByZXN1bHRzLg0KDQpgYGB7cn0NCmRlc2VxLmJibC5kYXRhIDwtIGxpc3QoKQ0KDQpmb3IgKHByb2plY3QgaW4gcHJvamVjdHMpIHsNCiAgZGVzZXEucmVzdWx0cyA8LSByZXNfZmVycm9wdG9zaXNbW3Byb2plY3RdXQ0KICBkZXNlcS5iYmwuZGF0YVtbcHJvamVjdF1dIDwtIGRhdGEuZnJhbWUoDQogICAgcm93Lm5hbWVzID0gcm93bmFtZXMoZGVzZXEucmVzdWx0cyksDQogICAgYmFzZU1lYW4gPSBkZXNlcS5yZXN1bHRzJGJhc2VNZWFuLA0KICAgIGxvZzJGb2xkQ2hhbmdlID0gZGVzZXEucmVzdWx0cyRsb2cyRm9sZENoYW5nZSwNCiAgICBsZmNTRSA9IGRlc2VxLnJlc3VsdHMkbGZjU0UsDQogICAgc3RhdCA9IGRlc2VxLnJlc3VsdHMkc3RhdCwNCiAgICBwdmFsdWUgPSBkZXNlcS5yZXN1bHRzJHB2YWx1ZSwNCiAgICBwYWRqID0gZGVzZXEucmVzdWx0cyRwYWRqLA0KICAgIGNhbmNlcl90eXBlID0gcHJvamVjdCwNCiAgICBnZW5lX3N5bWJvbCA9IGZlcnJvcHRvc2lzLmdlbmVzW3Jvd25hbWVzKGRlc2VxLnJlc3VsdHMpLCAiZ2VuZV9zeW1ib2wiXQ0KICApDQp9DQoNCmRlc2VxLmJibC5kYXRhLmNvbWJpbmVkIDwtIGJpbmRfcm93cyhkZXNlcS5iYmwuZGF0YSkNCmRlc2VxLmJibC5kYXRhLmNvbWJpbmVkIDwtIGRwbHlyOjpmaWx0ZXIoZGVzZXEuYmJsLmRhdGEuY29tYmluZWQsIGFicyhsb2cyRm9sZENoYW5nZSkgPj0gMS41ICYgcGFkaiA8IDAuMDUpDQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZA0KYGBgDQoNClBsb3QgdGhlIHJlc3VsdHMuDQoNCmBgYHtyfQ0KZGVzZXEuYmJsLmRhdGEuY29tYmluZWQgPC0gZGVzZXEuYmJsLmRhdGEuY29tYmluZWQgJT4lDQogIG11dGF0ZShmZHJfY2F0ZWdvcnkgPSBjdXQocGFkaiwNCiAgICBicmVha3MgPSBjKC1JbmYsIDFlLTE1LCAxZS0xMCwgMWUtNSwgMC4wNSksDQogICAgbGFiZWxzID0gYygiPDEwXi0xNSIsICIxMF4tMTAiLCAiMTBeLTUiLCAiMC4wNSIpLA0KICAgIHJpZ2h0ID0gRkFMU0UNCiAgKSkNCg0KdG9wX2dlbmVzIDwtIGRlc2VxLmJibC5kYXRhLmNvbWJpbmVkICU+JQ0KICBncm91cF9ieShjYW5jZXJfdHlwZSkgJT4lDQogIG11dGF0ZShyYW5rID0gcmFuaygtYWJzKGxvZzJGb2xkQ2hhbmdlKSkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHJhbmsgPD0gMTApICU+JQ0KICB1bmdyb3VwKCkNCg0KZ2dwbG90KHRvcF9nZW5lcywgYWVzKHkgPSBjYW5jZXJfdHlwZSwgeCA9IGdlbmVfc3ltYm9sLCBzaXplID0gZmRyX2NhdGVnb3J5LCBmaWxsID0gbG9nMkZvbGRDaGFuZ2UpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIikgKw0KICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSBzaXplcykgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbGltaXRzID0gYyhtaW4oZGVzZXEuYmJsLmRhdGEuY29tYmluZWQkbG9nMkZvbGRDaGFuZ2UpLCBtYXgoZGVzZXEuYmJsLmRhdGEuY29tYmluZWQkbG9nMkZvbGRDaGFuZ2UpKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgYW5nbGUgPSA5MCwgaGp1c3QgPSAxKQ0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgbGFicyhzaXplID0gIkZEUiIsIGZpbGwgPSAibG9nMiBGQyIsIHkgPSAiQ2FuY2VyIHR5cGUiLCB4ID0gIkdlbmUiKQ0KYGBgDQoNCiMjIyMgUHlyb3B0b3Npcw0KDQpGZXRjaCB0aGUgcHlyb3B0b3NpcyBnZW5lIHNldC4NCg0KYGBge3J9DQpweXJvcHRvc2lzLmdlbmVzIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJodW1hbiIsIGNhdGVnb3J5ID0gIkMyIiwgc3ViY2F0ZWdvcnkgPSAiQ1A6UkVBQ1RPTUUiKSAlPiUNCiAgZHBseXI6OmZpbHRlcihnc19uYW1lID09ICJSRUFDVE9NRV9QWVJPUFRPU0lTIikNCnB5cm9wdG9zaXMuZ2VuZXMNCmBgYA0KDQpGaWx0ZXIgdGhlIGdlbmVzIHRvIGluY2x1ZGUgb25seSB0aG9zZSBpbiB0aGUgcHlyb3B0b3NpcyBnZW5lIHNldC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCByZXN1bHRzPSJoaWRlIn0NCnRjZ2FfcHlyb3B0b3NpcyA8LSBsaXN0KCkNCg0KZm9yIChwcm9qZWN0IGluIHByb2plY3RzKSB7DQogIHJvd25hbWVzKHB5cm9wdG9zaXMuZ2VuZXMpIDwtIHB5cm9wdG9zaXMuZ2VuZXMkZW5zZW1ibF9nZW5lDQogIHRjZ2FfcHlyb3B0b3Npc1tbcHJvamVjdF1dIDwtIHRjZ2FfbWF0cml4W1twcm9qZWN0XV1bcm93bmFtZXModGNnYV9tYXRyaXhbW3Byb2plY3RdXSkgJWluJSBweXJvcHRvc2lzLmdlbmVzJGVuc2VtYmxfZ2VuZSwgXQ0KICB0Y2dhX3B5cm9wdG9zaXNbW3Byb2plY3RdXSA8LSB0Y2dhX3B5cm9wdG9zaXNbW3Byb2plY3RdXVssIHJvd25hbWVzKHNhbXBsZXNbW3Byb2plY3RdXSldDQoNCiAgIyBDaGVjayBpZiBhbGwgc2FtcGxlcyBpbiB0aGUgY291bnRzIGRhdGFmcmFtZSBhcmUgaW4gdGhlIHNhbXBsZXMgZGF0YWZyYW1lDQogIHByaW50KGFsbChjb2xuYW1lcyh0Y2dhX3B5cm9wdG9zaXNbW3Byb2plY3RdXSkgPT0gcm93bmFtZXMoKHNhbXBsZXNbW3Byb2plY3RdXSkpKSkNCn0NCmBgYA0KUGVyZm9ybSBkaWZmZXJlbnRpYWwgZ2VuZSBleHByZXNzaW9uIGFuYWx5c2lzLg0KDQpgYGB7cn0NCmRkc19weXJvcHRvc2lzIDwtIGxpc3QoKQ0KcmVzX3B5cm9wdG9zaXMgPC0gbGlzdCgpDQoNCmZvciAocHJvamVjdCBpbiBwcm9qZWN0cykgew0KICBwcmludChwcm9qZWN0KQ0KICBwcmludCgiPT09PT09PT09PT09PSIpDQoNCiAgZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoDQogICAgY291bnREYXRhID0gdGNnYV9weXJvcHRvc2lzW1twcm9qZWN0XV0sDQogICAgY29sRGF0YSA9IHNhbXBsZXNbW3Byb2plY3RdXSwNCiAgICBkZXNpZ24gPSB+dHlwZQ0KICApDQogIGRkcyA8LSBmaWx0ZXJfZ2VuZXMoZGRzLCBtaW5fY291bnQgPSAxMCkNCiAgZGRzJHR5cGUgPC0gcmVsZXZlbChkZHMkdHlwZSwgcmVmID0gIm5vcm1hbCIpDQogIGRkc19weXJvcHRvc2lzW1twcm9qZWN0XV0gPC0gREVTZXEoZGRzKQ0KICByZXNfcHlyb3B0b3Npc1tbcHJvamVjdF1dIDwtIHJlc3VsdHMoZGRzX3B5cm9wdG9zaXNbW3Byb2plY3RdXSkNCn0NCmBgYA0KDQpQcmV0dGlmeSB0aGUgZGlzcGxheSBvZiByZXN1bHRzLg0KDQpgYGB7cn0NCmRlc2VxLmJibC5kYXRhIDwtIGxpc3QoKQ0KDQpmb3IgKHByb2plY3QgaW4gcHJvamVjdHMpIHsNCiAgZGVzZXEucmVzdWx0cyA8LSByZXNfcHlyb3B0b3Npc1tbcHJvamVjdF1dDQogIGRlc2VxLmJibC5kYXRhW1twcm9qZWN0XV0gPC0gZGF0YS5mcmFtZSgNCiAgICByb3cubmFtZXMgPSByb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwNCiAgICBiYXNlTWVhbiA9IGRlc2VxLnJlc3VsdHMkYmFzZU1lYW4sDQogICAgbG9nMkZvbGRDaGFuZ2UgPSBkZXNlcS5yZXN1bHRzJGxvZzJGb2xkQ2hhbmdlLA0KICAgIGxmY1NFID0gZGVzZXEucmVzdWx0cyRsZmNTRSwNCiAgICBzdGF0ID0gZGVzZXEucmVzdWx0cyRzdGF0LA0KICAgIHB2YWx1ZSA9IGRlc2VxLnJlc3VsdHMkcHZhbHVlLA0KICAgIHBhZGogPSBkZXNlcS5yZXN1bHRzJHBhZGosDQogICAgY2FuY2VyX3R5cGUgPSBwcm9qZWN0LA0KICAgIGdlbmVfc3ltYm9sID0gcHlyb3B0b3Npcy5nZW5lc1tyb3duYW1lcyhkZXNlcS5yZXN1bHRzKSwgImdlbmVfc3ltYm9sIl0NCiAgKQ0KfQ0KDQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCA8LSBiaW5kX3Jvd3MoZGVzZXEuYmJsLmRhdGEpDQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCA8LSBkcGx5cjo6ZmlsdGVyKGRlc2VxLmJibC5kYXRhLmNvbWJpbmVkLCBhYnMobG9nMkZvbGRDaGFuZ2UpID49IDEuNSAmIHBhZGogPCAwLjA1KQ0KZGVzZXEuYmJsLmRhdGEuY29tYmluZWQNCmBgYA0KUGxvdCB0aGUgcmVzdWx0cy4NCg0KYGBge3J9DQpkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCA8LSBkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCAlPiUNCiAgbXV0YXRlKGZkcl9jYXRlZ29yeSA9IGN1dChwYWRqLA0KICAgIGJyZWFrcyA9IGMoLUluZiwgMWUtMTUsIDFlLTEwLCAxZS01LCAwLjA1KSwNCiAgICBsYWJlbHMgPSBjKCI8MTBeLTE1IiwgIjEwXi0xMCIsICIxMF4tNSIsICIwLjA1IiksDQogICAgcmlnaHQgPSBGQUxTRQ0KICApKQ0KDQp0b3BfZ2VuZXMgPC0gZGVzZXEuYmJsLmRhdGEuY29tYmluZWQgJT4lDQogIGdyb3VwX2J5KGNhbmNlcl90eXBlKSAlPiUNCiAgbXV0YXRlKHJhbmsgPSByYW5rKC1hYnMobG9nMkZvbGRDaGFuZ2UpKSkgJT4lDQogIGRwbHlyOjpmaWx0ZXIocmFuayA8PSAxMCkgJT4lDQogIHVuZ3JvdXAoKQ0KDQpnZ3Bsb3QodG9wX2dlbmVzLCBhZXMoeSA9IGNhbmNlcl90eXBlLCB4ID0gZ2VuZV9zeW1ib2wsIHNpemUgPSBmZHJfY2F0ZWdvcnksIGZpbGwgPSBsb2cyRm9sZENoYW5nZSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siKSArDQogIHNjYWxlX3NpemVfbWFudWFsKHZhbHVlcyA9IHNpemVzKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCBsaW1pdHMgPSBjKG1pbihkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCRsb2cyRm9sZENoYW5nZSksIG1heChkZXNlcS5iYmwuZGF0YS5jb21iaW5lZCRsb2cyRm9sZENoYW5nZSkpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBhbmdsZSA9IDkwLCBoanVzdCA9IDEpDQogICkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBsYWJzKHNpemUgPSAiRkRSIiwgZmlsbCA9ICJsb2cyIEZDIiwgeSA9ICJDYW5jZXIgdHlwZSIsIHggPSAiR2VuZSIpDQpgYGA=